package infra

import (
	"context"
	"encoding/base64"
	"fmt"
	"github.com/gogf/gf/v2/crypto/gaes"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/errors/gcode"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/net/ghttp"
	"github.com/gogf/gf/v2/os/glog"
	"github.com/gogf/gf/v2/os/gtime"
	"ruoyi-vue-pro-go/api/common"
	v1 "ruoyi-vue-pro-go/api/infra/v1"
	"ruoyi-vue-pro-go/internal/dao"
	"ruoyi-vue-pro-go/internal/model/do"
	"ruoyi-vue-pro-go/internal/model/entity"
	"ruoyi-vue-pro-go/internal/service"
)

type (
	sInfra struct{}
)

func init() {
	service.RegisterInfra(New())
}

func New() service.IInfra {
	return &sInfra{}
}

func (s *sInfra) GetDataSourceConfig(ctx context.Context, req *v1.GetDataSourceConfigReq) (res *v1.GetDataSourceConfigRes, err error) {
	res = &v1.GetDataSourceConfigRes{}
	err = dao.InfraDataSourceConfig.Ctx(ctx).Where(do.InfraDataSourceConfig{
		Deleted: false,
		Id:      req.Id,
	}).Scan(&res)
	return
}

func (s *sInfra) GetDataSourceConfigList(ctx context.Context, req *v1.GetDataSourceConfigListReq) (res *v1.GetDataSourceConfigListRes, err error) {
	res = &v1.GetDataSourceConfigListRes{}
	err = dao.InfraDataSourceConfig.Ctx(ctx).Where(do.InfraDataSourceConfig{
		Deleted: false,
	}).Scan(&res.List)
	return
}

func (s *sInfra) CreateDataSourceConfig(ctx context.Context, req *v1.CreateDataSourceConfigReq) (res *v1.CreateDataSourceConfigRes, err error) {
	res = &v1.CreateDataSourceConfigRes{}
	// 加密
	password := req.Password
	key := []byte("12345678901234567890123456789012") // 32字节，AES-256
	iv := []byte("1234567890123456")
	cipherText, err := gaes.EncryptCBC([]byte(password), key, iv)
	if err != nil {
		glog.Error(ctx, err)
	}
	// 输出Base64格式的加密结果
	encryptedBase64 := base64.StdEncoding.EncodeToString(cipherText)
	fmt.Printf("加密结果(Base64): %s\n", encryptedBase64)
	fmt.Printf("加密结果(Hex): %x\n", cipherText)
	req.Password = encryptedBase64
	// 这里需要获取当前用户名
	r := ghttp.RequestFromCtx(ctx)
	username := r.GetCtxVar("username").String()
	req.Creator = username
	req.Updater = username
	_, err = dao.InfraDataSourceConfig.Ctx(ctx).Data(req).Insert()
	if err != nil {
		return res, gerror.NewCode(gcode.CodeDbOperationError, "data source config create failed")
	}
	return
}

func (s *sInfra) GetDataSourceTableList(ctx context.Context, req *v1.GetDataSourceTableListReq) (res *v1.GetDataSourceTableListRes, err error) {
	res = &v1.GetDataSourceTableListRes{}
	dataSourceConfig, err := service.Infra().GetDataSourceConfig(ctx, &v1.GetDataSourceConfigReq{
		Id: req.DataSourceConfigId,
	})
	if err != nil {
		return res, gerror.NewCode(gcode.CodeDbOperationError, "data source config get failed")
	}
	key := []byte("12345678901234567890123456789012") // 32字节，AES-256
	iv := []byte("1234567890123456")
	decryptedBase64, _ := base64.StdEncoding.DecodeString(dataSourceConfig.Password)
	// 解密
	decryptedText, err := gaes.DecryptCBC(decryptedBase64, key, iv)
	if err != nil {
		glog.Error(ctx, err)
	}
	fmt.Printf("解密结果: %s\n", string(decryptedText))
	if err != nil {
		return res, gerror.NewCode(gcode.CodeDbOperationError, "data source config password decode failed")
	}
	link := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
		dataSourceConfig.Username, decryptedText, dataSourceConfig.Url, dataSourceConfig.Name)
	fmt.Println(link)
	// 查询SQL
	sql := "SHOW TABLE STATUS"
	// 查询条件
	if req != nil {
		// 表名称
		if req.Name != "" {
			sql += " WHERE Name like \"%" + req.Name + "%\""
		}
		// 表描述
		if req.Comment != "" {
			sql += " WHERE Comment like \"%" + req.Comment + "%\""
		}
	}
	// 对象转换
	dbConfig := gdb.ConfigNode{
		Type: "mysql",
		Link: link,
	}
	// 创建数据库连接
	db, err := gdb.New(dbConfig)
	if err != nil {
		return res, gerror.NewCode(gcode.CodeDbOperationError, "data source config connect failed")
	}

	// 测试连接
	//if _, err := db.Query(ctx, "SELECT 1"); err != nil {
	//	return res, gerror.NewCode(gcode.CodeDbOperationError, "data source config connect test failed")
	//}
	// 使用 Raw SQL 查询
	err = db.Raw(sql).Scan(&res.List)
	if err != nil {
		return nil, fmt.Errorf("查询MySQL表信息失败: %v", err)
	}
	return
}

func (s *sInfra) GetCodegenTablePage(ctx context.Context, req *v1.GetCodegenTablePageReq) (res *v1.GetCodegenTablePageRes, err error) {
	res = &v1.GetCodegenTablePageRes{
		List:          make([]*entity.InfraCodegenTable, 0),
		CommonPageRes: &common.CommonPageRes{},
	}
	model := dao.InfraCodegenTable.Ctx(ctx)
	if req.TableName != "" {
		model = model.WhereLike("table_name", "%"+req.TableName+"%")
	}
	if req.TableComment != "" {
		model = model.WhereLike("table_comment", "%"+req.TableComment+"%")
	}
	// 添加时间范围条件
	if len(req.CreateTime) != 0 {
		beginTime := gtime.New(req.CreateTime[0])
		endTime := gtime.New(req.CreateTime[1])
		if beginTime != nil && endTime != nil {
			// 验证时间顺序
			if beginTime.Time.After(endTime.Time) {
				return nil, gerror.New("开始时间不能晚于结束时间")
			}

			model = model.WhereBetween("create_time", beginTime, endTime)
		} else if beginTime != nil {
			model = model.WhereGTE("create_time", beginTime)
		} else if endTime != nil {
			model = model.WhereLTE("create_time", endTime)
		}
	}
	if req.PageSize != 0 {
		res.PageNo = req.PageNo
		res.PageSize = req.PageSize
		model = model.Page(req.PageNo, req.PageSize)
	}
	err = model.ScanAndCount(&res.List, &res.Total, false)
	return
}
